<?php
/**
 * Copyright (c) [2019] [吴跃忠]
 * [selibra] is licensed under the Mulan PSL v1.
 * You can use this software according to the terms and conditions of the Mulan PSL v1.
 * You may obtain a copy of Mulan PSL v1 at:
 * http://license.coscl.org.cn/MulanPSL
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v1 for more details.
 */

namespace Selibra\Http\Lib;


use Selibra\Di\Container\ContainerCollector;
use Selibra\Di\DI;
use Selibra\Event\EventTrigger;
use Selibra\Http\Annotations\RequestInterceptor;
use Selibra\Http\Events\HttpOnRequestAfterEvent;
use Selibra\Http\Events\HttpRouterCallAfterEvent;
use Selibra\Http\Events\HttpRouterCallBeforeEvent;
use Selibra\Http\Protocol\HttpResponseInterface;
use Selibra\Http\Protocol\RequestInterceptorInterface;
use Selibra\Http\Protocol\ResponseDataInterface;
use Swoole\Event;
use Swoole\Http\Server;
use Selibra\Http\Exception\PageNotFoundException;
use Selibra\Http\Exception\ResponseException;
use Selibra\Http\Route\Router;
use Selibra\Tools\Console;

class Actuator
{

    /**
     * @var Request
     */
    private Request $request;


    /**
     * @var HttpResponseInterface
     */
    private HttpResponseInterface $response;


    /**
     * @var Router
     */
    protected Router $router;


    public function __construct(Request $request, Response $response)
    {
        $this->router = new Router();
        $this->router->setRequest($request);

        $this->request = $request;
        $this->response = $response;
    }


    /**
     * 请求正式执行操作
     * @return mixed|Response
     * @throws \ReflectionException
     * @throws PageNotFoundException
     */
    public function exec()
    {
        // 执行系统
        $controllerNamespace = $this->router->getControllerNamespace();

        // 设置一个路由参数
        $this->request->setRouteParams($this->router->getRouteParams());
        if (empty($controllerNamespace)) {
            throw new PageNotFoundException("路由找不到");
        }

        // 生成Session对象
        $session = SessionFactory::gen($this->request, $this->response);

        // 【事件】路由调用之前
        EventTrigger::listener((new HttpRouterCallBeforeEvent($session)));

        // 获取路由参数
        $reflectionMethod = new \ReflectionMethod($controllerNamespace, $this->router->getMethodName());
        $parameterList = [];
        foreach ($reflectionMethod->getParameters() as $parameter) {
            // 配置参数
            $parameterList[$parameter->getName()] = $parameter;
        }

        try {
            /** @var Interceptor $interceptor */
            $interceptor = DI::getObjectContext(Interceptor::class);
            $interceptor->setPathInfo($this->request->getPathInfo())
                ->before($session);

            /** @var HttpController $controller */
            $controller = DI::getObjectContext($controllerNamespace);

            if ($controller instanceof HttpController) {
                $controller->__setRequest($this->request);
                $controller->__setResponse($this->response);
                $controller->__setSession($session);

                // 实例化并执行开始方法
                $controller->__begin();

                // 调用控制器方法
                $paramArray = $this->params($parameterList);
            } else {
                // 调用控制器方法
                $paramArray = [$session];
            }
            $data = call_user_func_array([$controller, $this->router->getMethodName()], $paramArray);
        } catch (ResponseException $responseException) {
            $data = $responseException->getResponse();
        }
        // 其他接口输出的数据
        if ($data instanceof ResponseDataInterface) {
            // 如果是来源于HttpResponseInterface
            $data = $data->getResponse();
        } else if (!is_object($data)) {
            // 如果是字符串
            $this->response->setContent($data);
            $data = $this->response;
        }

        // 后置调用
        $interceptor->after($data);

        // 【事件】Http请求结束
        EventTrigger::listener((new HttpRouterCallAfterEvent($session, $data)));
        return $this->response;
    }


    /**
     * @param \ReflectionParameter[] $parameterList
     * @return array
     */
    protected function params(array $parameterList)
    {
        $params = [];
        foreach ($parameterList as $parameter) {
            $parameterClass = $parameter->getClass();
            if ($this->request->getMethod() == 'POST') {
                $data = $this->request->getPost($parameter->getName());
            } else {
                $data = $this->request->getGet($parameter->getName());
            }
            if (empty($data)) {
                try {
                    $data = $parameter->getDefaultValue();
                } catch (\ReflectionException $reflectionException) {
                    $data = null;
                }
            }
            if (!empty($parameterClass)) {
                $parameterClassName = $parameterClass->getName();
                $parameterClass = new $parameterClassName($data, $this->response);
                $params[] = $parameterClass;
            } else {
                $params[] = $data;
            }
        }
        return $params;
    }


    /**
     * 内存回收
     */
    public function __destruct()
    {
        // 内存回收
        gc_collect_cycles();
    }


}
